home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
mxlibs
/
sbdsp2b
/
voc2rpd.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-01-21
|
19KB
|
416 lines
Program ConvertVOCRPD;
(**************************************************************************)
(* Program VOC2RPD *)
(* By: Romesh Prakashpalan *)
(**************************************************************************)
(* This program will convert a VOC file to my RPD format (the specs have *)
(* been given out with my SBDSP unit). This will eliminate any "noise" *)
(* you might get due to the fact that you are probably reading in VOC *)
(* data structures instead of pure RAW data. *)
(* Any questions or comments (or donations ;-) ) should be directed to: *)
(* Romesh Prakashpalan (hacscb93@huey.csun.edu) <- Until 01/31/94. *)
(* Note: After 01/31/94, my account at CSUN expires, so look in the *)
(* comp.lang.pascal or alt.sb.programmer newsgroups, for my *)
(* current address. *)
(**************************************************************************)
Uses SBDSP, Crt;
(**************************************************************************)
(* Revisions: *)
(* Version 1.0α: Just strips off the VOC file header, to reduce a bit *)
(* of the "popping" that occurs when played back as a RAW*)
(* file. This was pretty lame! *)
(* Version 1.10: Converts the file pretty much with all VOC specific *)
(* information removed. However, repeat loops will only *)
(* iterate ONCE, and Silence blocks will be REMOVED from *)
(* the VOC file. In future versions, I plan on adding *)
(* repeats manually, digital silence (if user specifies *)
(* it), but these are minor things. *)
(* Version 1.11: STOOPID MISTAKE FIXED!!!! Would not write header to *)
(* the beginning of the file, but rather to the END!! *)
(* Version 1.12: Added Input/Output checking on files, instead of *)
(* the program giving a "run-time error", it gives a *)
(* suitable error message. *)
(* Version 1.13: Fixed a Block 9 error in conversion (Previously I *)
(* did not have any VOC files to test Block 9 conversion *)
(* on, so I apologize!). At this point, most SERIOUS *)
(* conversion flaws should have been recognized. *)
(**************************************************************************)
(* Future Revisions: *)
(* I hope to create support for 16-bit sound in the next versions of my *)
(* code, but this is dependant on when I will be able to get code to *)
(* program the Sound Blaster 16! Only then will I be able to implement *)
(* such a conversion, as my program is the only one which will read, or *)
(* even recognise an RPD file! (As far as I know) *)
(**************************************************************************)
(* Note: To all of those who are using this file for the SBDSP unit that *)
(* I have given out: What do you think of my unit???, do you think *)
(* that I should create support for the Sound Blaster 16? I do not *)
(* think that I should charge anything for it, as that would make *)
(* me as bad as Creative Labs, but I would willingly take a small *)
(* donation ;-). That's all right, just as long as you are able to *)
(* use the code, I'm happy. Please let me know what you think about*)
(* the unit though! *)
(**************************************************************************)
type
(****************************************************************************)
(* Channel method: 0 - Layed down Byte 1 - Channel 0, Byte 2 - Channel 1... *)
(* 1 - First Channel continuously for Size Bytes, then comes*)
(* the Second Channel, etc... *)
(****************************************************************************)
RPDHeader = Record
Sig: Array [0..2] of Char; (* "RPD" *)
Version: Word; (* Version # *)
DAC: Byte; (* 8/16/4/4.6/2/2.6, etc...*)
Phase: Byte; (* Mono=0, Stereo=1, Surround=2*)
Freq: Word; (* Sample Frequency *)
Channels: Byte; (* # of DIGITAL Channels *)
ChannelMethod: Byte; (* Method for laying down channels *)
Size: LongInt; (* Size of Sample *)
Reserved: Array [0..31] of Byte;
end;
VOCHeader = Record
Sig:Array [0..$13] of Char;(* "Creative Voice File" *)
Offset: Word; (* Offset of first datablock in the*)
(* .VOC file. *)
Version: Word; (* Version # *)
Version2s: Word; (* 2's complement of version # plus*)
(* 1234h ex: 1.10 = 1129 *)
end;
ThreeByte = Array [1..3] of Byte;
Block1Type = Record (* Voice Data Block *)
Length: ThreeByte;
TimeConstant: Byte; (* = 256 - 1000000/Sample Rate *)
PackType: Byte; (* 0 = 8-bit unpacked *)
(* 1 = 4-bit packed *)
(* 2 = 2.6 bit packed *)
(* 3 = 2-bit packed *)
end;
Block2Type = Record (* Voice Continuation *)
Length: ThreeByte;
end;
Block3Type = Record (* Silence block *)
Length: ThreeByte; (* Always 3 *)
Pause: Word; (* Pause period in sample bytes *)
TimeConstant: Byte;
end;
Block4Type = Record (* Marker Block *)
Length: ThreeByte;
MarkerValue: Word;
end;
Block5Type = Record (* Ascii Text (null-terminated) *)
Length: ThreeByte;
end;
Block6Type = Record (* Repeat Loop *)
Length: ThreeByte; (* Always 2 *)
Count: Word; (* 1 to $FFFE, $FFFF = endless loop*)
end;
Block7Type = Record (* End Repeat Loop *)
Length: ThreeByte; (* Always 0 *)
end;
Block8Type = Record (* Extended Block *)
Length: ThreeByte; (* Always 4 *)
TimeConstant: Word; (* For Mono: *)
(* 65535-(256,000,000/sample rate)*)
(* For Stereo: *)
(* 65535-(256000000/sample rate*2) *)
PackType: Byte; (* Same as Block 1 *)
Mode: Byte; (* 0 = Mono, 1 = Stereo *)
end;
Block9Type = Record (* NEW Extended VOC Block *)
Length: ThreeByte; (* Length of Sample + 12 (Bytes) *)
SamplesPerSec: LongInt; (* ACTUAL Samples/Second *)
BitsPerSample: Byte; (* Bits/Sample after compression *)
Channels: Byte; (* 1 for mono, 2 for stereo *)
FormatTag: Word; (* Format Tags follow: *)
(* $000 - 8 bit unsigned PCM *)
(* $001 - 4 Bit ADPCM *)
(* $002 - 2.6 Bit ADPCM *)
(* $003 - 2 Bit ADPCM *)
(* $004 - 16 Bit Signed PCM *)
(* $006 - CCITT a-Law *)
(* $007 - CCITT u-Law *)
(* $200 - 16 bit -> 4 Bit ADPCM *)
Reserved: LongInt; (* Reserved by Creative Labs *)
end;
var
Source, Destination: String;
Ch: Char;
Function ThreeByte2Long (TheData: ThreeByte): LongInt;
Begin
ThreeByte2Long := LongInt (TheData[1]) + LongInt (TheData[2]) shl 8 +
LongInt (TheData[3]) shl 16;
End;
Procedure ConvertVOC2RPD (Source, Destination: String);
var
SourceF: File;
DestF: File;
TempRPDHead: RPDHeader;
TempVOCHead: VOCHeader;
TempBuffer: Pointer;
BlockType: Byte;
BytesConverted: LongInt;
Done: Boolean;
Block1: Block1Type;
Block2: Block2Type;
Block3: Block3Type;
Block4: Block4Type;
Block5: Block5Type;
Block6: Block6Type;
Block7: Block7Type;
Block8: Block8Type;
Block9: Block9Type;
LeftToGo: LongInt;
SkipNextBlock1: Boolean;
Begin
SkipNextBlock1 := False;
BytesConverted := 0;
Assign (SourceF, Source);
Assign (DestF, Destination);
Reset (SourceF, 1);
Rewrite (DestF, 1);
BlockRead (SourceF, TempVOCHead, SizeOf (TempVOCHead));
GetMem (TempBuffer, $FFFF);
TempRPDHead.Sig := 'RPD';
TempRPDHead.Version := 1;
TempRPDHead.Channels := 1;
TempRPDHead.ChannelMethod := 0;
(* Blank out the reserved field with 0's, so that future software won't *)
(* be confused! *)
FillChar (TempRPDHead.Reserved, SizeOf (TempRPDHead.Reserved), 0);
(* Write the incomplete header to the file, we shall update it later... *)
BlockWrite (DestF, TempRPDHead, SizeOf (TempRPDHead));
Done := False;
Repeat
BlockRead (SourceF, BlockType, SizeOf (BlockType));
Case BlockType of
0: Begin (* Terminator Block *)
WriteLn ('Block Type 0 encountered, conversion complete...');
Done := True;
End;
1: Begin (* Data Block *)
Write ('Converting Block Type 1.');
BlockRead (SourceF, Block1, SizeOf (Block1));
If not SkipNextBlock1 then
Begin
Case Block1.PackType of
0: TempRPDHead.DAC := EightBitDMA;
1: TempRPDHead.DAC := FourBitDMA;
2: TempRPDHead.DAC := TwoSixBitDMA;
3: TempRPDHead.DAC := TwoBitDMA;
end;
TempRPDHead.Freq := Round (1000000/(256 - Block1.TimeConstant));
TempRPDHead.Phase := 0; (* Block Type 1 is ALWAYS MONO *)
End
Else SkipNextBlock1 := False;
Inc (BytesConverted, ThreeByte2Long (Block1.Length)-2);
LeftToGo := ThreeByte2Long (Block1.Length) - 2;
Repeat
If LeftToGo > $FFFF then
Begin
Dec (LeftToGo, $FFFF);
BlockRead (SourceF, TempBuffer^, $FFFF);
BlockWrite (DestF, TempBuffer^, $FFFF);
End
Else
Begin
BlockRead (SourceF, TempBuffer^, LeftToGo);
BlockWrite (DestF, TempBuffer^, LeftToGo);
LeftToGo := 0;
End;
Write ('.');
Until LeftToGo = 0;
WriteLn;
WriteLn ('Block Type 1: ', ThreeByte2Long (Block1.Length),
' bytes converted.');
end;
2: Begin (* Voice Continuation *)
WriteLn ('Converting Block 2, Voice Continuation.');
BlockRead (SourceF, Block2, SizeOf (Block2));
Inc (BytesConverted, ThreeByte2Long (Block2.Length));
LeftToGo := ThreeByte2Long (Block2.Length);
Repeat
If LeftToGo > $FFFF then
Begin
Dec (LeftToGo, $FFFF);
BlockRead (SourceF, TempBuffer^, $FFFF);
BlockWrite (DestF, TempBuffer^, $FFFF);
End
Else
Begin
BlockRead (SourceF, TempBuffer^, LeftToGo);
BlockWrite (DestF, TempBuffer^, LeftToGo);
LeftToGo := 0;
End;
Write ('.');
Until LeftToGo = 0;
WriteLn;
WriteLn ('Block Type 2: ', ThreeByte2Long (Block1.Length),
' bytes converted.');
end;
3: Begin (* Silence Block, will be skipped *)
WriteLn ('Skipping a Silence Block (Block Type 3)');
BlockRead (SourceF, Block3, SizeOf (Block3));
end;
4: Begin (* Marker Block *)
WriteLn ('Skipping a Marker Block (Block Type 4)');
BlockRead (SourceF, Block4, SizeOf (Block4));
End;
5: Begin (* ASCII text *)
WriteLn ('Skipping embedded ASCII text (Block Type 5)');
BlockRead (SourceF, Block5, SizeOf (Block5));
End;
6: Begin (* Repeat Loop, in version 1.10, they are skipped *)
WriteLn ('Skipping the repeat loop, loop will play ONCE');
BlockRead (SourceF, Block6, SizeOf (Block6));
End;
7: Begin (* Signal the end of a repeat loop *)
WriteLn ('End of Repeat Loop found...');
BlockRead (SourceF, Block7, SizeOf (Block7));
End;
8: Begin (* Extended Block (Stereo, and other 8-bit goodies) *)
WriteLn ('An extended block was found (8), reading data...');
SkipNextBlock1 := True;
BlockRead (SourceF, Block8, SizeOf (Block8));
Case Block8.PackType of
0: TempRPDHead.DAC := EightBitDMA;
1: TempRPDHead.DAC := FourBitDMA;
2: TempRPDHead.DAC := TwoSixBitDMA;
3: TempRPDHead.DAC := TwoBitDMA;
end;
If Block8.Mode = 0 then
Begin
TempRPDHead.Phase := 0;
TempRPDHead.Freq := (-256000000 div (Block8.TimeConstant
- 65536));
End
Else
Begin
TempRPDHead.Phase := 1;
TempRPDHead.Freq := (-256000000 div (Block8.TimeConstant
- 65536));
End;
End;
9: Begin (* NEW Extended Block (16-Bit/other NEW stuff) *)
Write ('Converting Block 9.');
BlockRead (SourceF, Block9, SizeOf (Block9));
TempRPDHead.Freq := Block9.SamplesPerSec;
TempRPDHead.DAC := 0;
Inc (BytesConverted, ThreeByte2Long (Block9.Length));
Case Block9.FormatTag of
$000: TempRPDHead.DAC := EightBitDMA;
$001: TempRPDHead.DAC := FourBitDMA;
$002: TempRPDHead.DAC := TwoSixBitDMA;
$003: TempRPDHead.DAC := TwoBitDMA;
$004: Begin
TempRPDHead.DAC := SixteenBitDMA;
WriteLn ('HA! Sixteen Bit DAC found!');
End;
(* All other types are undefined in my program as of now!*)
(* These will be the Sixteen Bit Compression types *)
end;
TempRPDHead.Phase := (Block9.Channels - 1);
If TempRPDHead.Phase = 1 then
TempRPDHead.Freq := TempRPDHead.Freq * 2;
LeftToGo := ThreeByte2Long (Block9.Length) - 12;
Repeat
If LeftToGo > $FFFF then
Begin
Dec (LeftToGo, $FFFF);
BlockRead (SourceF, TempBuffer^, $FFFF);
BlockWrite (DestF, TempBuffer^, $FFFF);
End
Else
Begin
BlockRead (SourceF, TempBuffer^, LeftToGo);
BlockWrite (DestF, TempBuffer^, LeftToGo);
LeftToGo := 0;
End;
Write ('.');
Until LeftToGo = 0;
WriteLn;
WriteLn ('Block Type 9: ', ThreeByte2Long (Block9.Length) - 12,
' bytes converted.');
End;
end;
Until Done;
TempRPDHead.Size := BytesConverted;
FreeMem (TempBuffer, $FFFF);
Seek (DestF, 0);
(* Now, write the completed information... *);
BlockWrite (DestF, TempRPDHead, SizeOf (TempRPDHead));
Close (SourceF);
Close (DestF);
WriteLn ('File conversion done...');
WriteLn ('***************************************************');
Write ('Mode: ');
Case TempRPDHead.Phase of
0: WriteLn ('Mono');
1: WriteLn ('Stereo');
end;
Case TempRPDHead.Dac of
EightBitDMA: WriteLn ('8 Bit (unpacked)');
FourBitDMA: WriteLn ('4 Bit (packed)');
FourBitRefDMA: WriteLn ('4 Bit w/Reference Byte (packed)');
TwoSixBitDMA: WriteLn ('2.6 Bit (packed)');
TwoSixBitRefDMA: WriteLn ('2.6 Bit w/Reference Byte (packed)');
TwoBitDMA: WriteLn ('2 Bit (packed)');
TwoBitRefDMA: WriteLn ('2 Bit w/Reference Byte (packed)');
end;
If TempRPDHead.Phase = 1 then TempRPDHead.Freq := TempRPDHead.Freq div 2;
WriteLn ('Frequency: ', TempRPDHead.Freq, ' Hz');
WriteLn ('***************************************************');
End;
Function FileExists (Filename: String): Boolean;
var
F: file;
Begin
{$I-}
Assign(F, FileName);
FileMode := 0; (* Set file access to read only *)
Reset(F);
Close(F);
{$I+}
FileExists := (IOResult = 0) and (FileName <> '');
End;
Begin
Clrscr;
WriteLn (' VOC2RPD version 1.13, By: Romesh Prakashpalan, 1994');
WriteLn (' VOC2RPD is FREEWARE ');
Write ('Enter in VOC file to be converted: ');
ReadLn (Source);
If not FileExists (Source) then
Begin
WriteLn ('Source File Doesn''t Exist!');
Halt;
End;
Write ('Enter in RPD file to convert to: ');
ReadLn (Destination);
If FileExists (Destination) then
Begin
Write ('File exists! overwrite? (''N'' for No, any other key kills it): ');
Ch := UpCase (Readkey);
WriteLn (Ch);
If Ch = 'N' then Halt;
End;
ConvertVOC2RPD (Source, Destination);
End.